/**
 * \file  biLAV_test.cpp
 * \brief Definition of biLAV_test class.
 *
 * LAV: Lib Anti Virals
 * <http://lav.googlecode.com/>
 * Copyright (C) 2013 Alberione Fernando, Ocampo Emanuel FuDePAN
 *
 * This file is part of the LAV project.
 *
 * Contents:       Cpp file for LAV providing class biLAV_test.
 *
 * System:         LAV
 * Language:       C++
 *
 * Author:         Alberione Fernando
 * E-Mail:         falberione037@gmail.com
 *
 * Author:         Ocampo Emanuel
 * E-Mail:         eocampo86@gmail.com
 *
 * LAV is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LAV is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LAV.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <gtest/gtest.h>
#include <mili/mili.h>
#include "lav/data_base.h"
#include "lav/antiviral_set.h"

using namespace lav;
using namespace std;


DataBase db;
AntiviralSet all_antivirals;
PossibleMutants::PosAminoacidsTripletsContainer join_all_antivirals;

TEST(Test_biLAV, Join)
{
  // PossibleMutants::Pos_Aminoacids_Triplets_Container join_all_antivirals;
   db.load_file("./ref/antivirals_biLAV.xml");
   db.get_antivirals(all_antivirals);

   //Posiciones de resistencias esperadas
   const int positions_expect[12] = {163, 172, 213, 282, 168, 49, 83, 87, 46, 53, 75, 31};

   //Cantidad de aminoacidos esperados por posicion
   const int cant_amins_for_positions_expect[12] = {1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1};

   //Aminoacidos esperados por posicion
   const char* amins_expect[14] = {"r", "v", "f", "v", "e", "l", "v", "s", "v", "a", "m", "l", "v", "i"};

   //Cantidad de codones esperados por posicion
   const int cant_triplets_expect[14] = {6, 4, 2, 4, 2, 6, 4, 6, 4, 4, 1, 6, 4, 3};

   //Codones esperados para cada aminoacido, segun su posicion
   const char* triplets_expect[56] = {"CGU","CGC","CGA","CGG","AGA","AGG","GUU","GUC","GUA",
                                      "GUG","UUU","UUC","GUU","GUC","GUA","GUG","GAA","GAG",
                                      "UUA","UUG","CUU","CUC","CUA","CUG","GUU","GUC","GUA",
                                      "GUG","UCU","UCC","UCA","UCG","AGU","AGC","GUU","GUC",
                                      "GUA","GUG","GCU","GCC","GCA","GCG","AUG","UUA","UUG",
                                      "CUU","CUC","CUA","CUG","GUU","GUC","GUA","GUG","AUU",
                                      "AUC","AUA"};

   //Cantidad de antivirales cargados desde la Base de Datos
   ASSERT_EQ(all_antivirals.size(), 5);
   all_antivirals.mutants.join_antivirals(join_all_antivirals);

   //Cantidad de posiciones agrupadas
   ASSERT_EQ(join_all_antivirals.size(), 12);
   PossibleMutants::PosAminoacidsTripletsContainer::const_iterator it_join;
   PossibleMutants::AminoacidTripletsContainer amins_triplets;
   PossibleMutants::AminoacidTripletsContainer::const_iterator it_amin_triplets;
   PossibleMutants::TripletVector triplets;
   TripletList::const_iterator it_triplets;
   size_t i = 0;
   size_t j = 0;
   size_t m = 0;
   for(it_join = join_all_antivirals.begin(); it_join != join_all_antivirals.end(); ++it_join)
   {
       //Se verifican las posiciones de resistencia agrupadas
       EXPECT_EQ(it_join->pos_resistance, positions_expect[i]);
       amins_triplets = it_join->aminoacids_triplets;

       //Se verifica la cantidad de aminoacidos agrupados para la posicion corriente
       ASSERT_EQ(amins_triplets.size(), cant_amins_for_positions_expect[i]);
       for(it_amin_triplets = amins_triplets.begin(); it_amin_triplets != amins_triplets.end(); ++it_amin_triplets)
       {
           //Se verifican los aminoacidos agrupados para la posicion corriente
           EXPECT_STREQ((it_amin_triplets->aminoacid).c_str(), amins_expect[j]);
           triplets = it_amin_triplets->triplets;

           //Se verifica la cantidad de codones correspondientes al aminoacido corriente
           ASSERT_EQ(triplets.size(), cant_triplets_expect[j]);
           for(size_t k = 0; k < triplets.size(); ++k)
           {
               //Se verifican los codones correspondientes al aminoacido corriente
               EXPECT_STREQ((triplets[k].to_string()).c_str(), triplets_expect[m]);
               ++m;
           }
           ++j;
       }
       ++i;
   }
}

TEST(Test_biLAV, BasesMutants_And_Coefficients)
{
   //Bases esperadas
   const int values_bases_expect[12] = {7, 5, 3, 5, 3, 7, 5, 7, 9, 8, 5, 4};

   //Coeficientes esperados
   const uint64_t values_coefficient_expect[12] = {1, 4, 20, 160, 1440, 10080, 50400, 352800,
                                                   1058400, 5292000, 15876000, 79380000};
   PossibleMutants possible_mutants(join_all_antivirals);

   //Verifica el tamanio de la mutante (cantidad de bases que forman el numero)
   ASSERT_EQ(possible_mutants.get_mutantSize(), 12);

   //Verifica la cantidades de bases que forman el numero en base mixta
   ASSERT_EQ(possible_mutants.get_numberBases(), 12);

   //Verifica la cantidad de coeficientes
   ASSERT_EQ(possible_mutants.get_numberMutants_coefficients(), 12);

   //Verifica la cantidad de mutantes posibles
   ASSERT_EQ(possible_mutants.get_maxNumber_mutants(), 555659999);
   for(size_t i = 0; i < possible_mutants.get_mutantSize(); ++i)
   {
       //Verifica que la base corriente sea correcta
       EXPECT_EQ(possible_mutants.get_base(i), values_bases_expect[i]);

       //Verifica que el coeficiente corriente sea correcto
       EXPECT_EQ(possible_mutants.get_coefficient(i), values_coefficient_expect[i]);
   }
}

TEST(Test_biLAV, Applicable_and_Mutants)
{
    ArvsSet::const_iterator it_arvs;
    PossibleMutants::PopulationsIds::const_iterator it_mutant;
    PossibleMutants::PopulationsIds mutants;
    AntiviralSet antivirals_applicable;
    PossibleMutants::Id current_id;
    PossibleMutants::Id id = 350321;
    PossibleMutants possible_mutants(join_all_antivirals);
    //Antivirales aplicables esperados
    const char* first_arvs_expect [2] = {"Abacabir", "Tenofovir"};
    all_antivirals.mutants.get_applicable(join_all_antivirals, possible_mutants, id, antivirals_applicable);

    //Verifica la cantidad de antivirales aplicables a la mutante 350321
    ASSERT_EQ(antivirals_applicable.size(), 2);
    size_t i = 0;
    AntiviralsNames av_name;
    for(it_arvs = antivirals_applicable.begin(); it_arvs != antivirals_applicable.end(); ++it_arvs)
    {
        (*it_arvs)->get_attrib("name", av_name);

       //Verifica que el antiviral corriente sea correcto
       EXPECT_STREQ(av_name.c_str(), first_arvs_expect[i]);
       ++i;
   }

   //Mutantes esperadas de la aplicacion de los antivirales "Abacabir" y "Tenofovir"
   const PossibleMutants::Id mutants_expect [114] = {75143921, 69851921, 59267921, 53975921, 43391921, 38099921,
                                 27515921, 22223921, 74791121, 69499121, 58915121, 53623121, 43039121, 37747121,
                                 27163121, 21871121, 550718321, 545426321, 534842321, 529550321, 518966321, 513674321,
                                 503090321, 497798321, 471338321, 466046321, 455462321, 450170321, 439586321, 434294321,
                                 423710321, 418418321, 391958321, 386666321, 376082321, 370790321, 360206321, 354914321,
                                 344330321, 339038321, 312578321, 307286321, 296702321, 291410321, 280826321, 275534321,
                                 264950321, 259658321, 233198321, 227906321, 217322321, 212030321, 201446321, 196154321,
                                 185570321, 180278321, 153818321, 148526321, 137942321, 132650321, 122066321, 116774321,
                                 106190321, 100898321, 5289521, 4231121, 3172721, 2114321, 4936721, 3878321, 2819921,
                                 1761521, 480863921, 479805521, 478747121, 477688721, 401483921, 400425521, 399367121,
                                 398308721, 322103921, 321045521, 319987121, 318928721, 242723921, 241665521, 240607121,
                                 239548721, 163343921, 162285521, 161227121, 160168721, 83963921, 82905521, 81847121,
                                 80788721, 477335921, 476983121, 397955921, 397603121, 318575921, 318223121, 239195921,
                                 238843121, 159815921, 159463121, 80435921, 80083121, 476630321, 397250321, 317870321,
                                 238490321, 159110321, 79730321};
 
   all_antivirals.mutants.get_mutants(join_all_antivirals, possible_mutants, antivirals_applicable, id, mutants);

   //Verifica la cantidad de mutantes resultantes 
   ASSERT_EQ(mutants.size(), 114);
   i = 0;
   for(it_mutant = mutants.begin(); it_mutant != mutants.end(); ++it_mutant)
   {
       current_id = *it_mutant;

       //Verifica que la mutante resultante corriente sea correcta
       EXPECT_EQ(current_id, mutants_expect[i]);
       ++i;
   }
}


TEST(Test_biLAV, sequence_from_id_AND_id_from_sequence)
{
    biopp::NucSequence sequence;
    biopp::PseudoNucSequence pseudo_sequence;
    PossibleMutants::Id id = 350321;
    PossibleMutants possible_mutants(join_all_antivirals);
    load_sequence("./ref/init_seq_biLAV.txt", pseudo_sequence);
    pseudoNucSequence_to_nucSequence(pseudo_sequence, sequence);

    //Se obtiene la secuencia mutante que representa id
    all_antivirals.mutants.get_sequence_from_id(join_all_antivirals, possible_mutants, id, sequence);

    //Se verifica que el identificador de la secuencia mutante sea el esperado
    EXPECT_EQ(id, all_antivirals.mutants.get_id_from_sequence(join_all_antivirals, possible_mutants, sequence));
}

TEST(Test_biLAV, get_applicable_populations_AND_get_mutants_populations)
{
    AntiviralSet antivirals_applicable;
    PossibleMutants::PopulationsIds all_mutants;
    PossibleMutants::PopulationsIds ids;
    PossibleMutants::Id id1 = 350321;
    PossibleMutants::Id id2 = 2;
    PossibleMutants::Id id3 = 1;
    mili::insert_into(ids, id1);
    mili::insert_into(ids, id2);
    mili::insert_into(ids, id3);
    all_antivirals.mutants.get_applicable_populations(ids, antivirals_applicable);

    //Verifica que la cantidad de antivirales que aplican sean correctos
    EXPECT_EQ(antivirals_applicable.size(), 2);
    all_antivirals.mutants.get_mutants_populations(ids, antivirals_applicable, all_mutants);

    //Verifica que la cantidad de mutantes resultantes sea correcta
    EXPECT_EQ(all_mutants.size(), 342);
}

TEST(Test_biLAV, get_mutants_catch_up)
{
    PossibleMutants::PopulationsIds mutants_catch_up;
    PossibleMutants::Id id = 350321;
    all_antivirals.mutants.get_mutants_catch_up(id, mutants_catch_up);

    //Verifica que la cantidad de mutantes alcanzables sea correcta
    EXPECT_EQ(mutants_catch_up.size(), 115);
}